using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace FallenValkyrie {
    
    public class Game1 : Microsoft.Xna.Framework.Game {
/*******************************************************/
//                  Variables                          //
/*******************************************************/
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        KeyboardState oldKey;

        public SpriteBatch SpriteBatch
        {
            get { return spriteBatch; }
        }

        // System
        int screenWidth;
        int screenHeight;
        bool win = false;
        bool pause = false;

        // Font
        SpriteFont font;

        // Level
        Texture2D bg_layer0;
        Texture2D bg_stair;
        Texture2D bg_ground;
        Texture2D bg_stars;
        Texture2D obj;
        Texture2D obj2;
        Texture2D obj3;
        Texture2D obj4;
        Texture2D obj5;
        Texture2D obj6;
        Texture2D bg_mounts;
        
        // Player
        Rectangle playerRect;
        int direction;

        // Enemy

        // GUI
        Texture2D hp_mp_bar;
        Texture2D hp_mp_con;
        //Texturplayeplayer.cutSceneMove = "run to right";r.e2D skill_1;
        Texture2D skill_2;
        Texture2D skill_3;

        // Start Menu
        Texture2D start_background;
        Texture2D play_s;
        Texture2D credits_s;
        Texture2D quit_s;
        Texture2D resume_s;
        Texture2D resume_us;
        Texture2D play_us;
        Texture2D credits_us;
        Texture2D quit_us;

        Song startMenuMusic;

        // Items
        Texture2D hpPot;
        Texture2D mpPot;

        // Credits
        Texture2D credits_bg;



/*******************************************************/
//                  Class                              //
/*******************************************************/
        // Class 
        GUI gui;
        Level level;
        Song levelMusic;

        Explosion explosion;

        //EnemyGenerator enemyGenerator = new EnemyGenerator(0, 2.5f, 100);
        
        //List<EnemyType1> enemyList = new List<EnemyType1>();
        //List<EnemyType1> deadEnemyList = new List<EnemyType1>();
        EnemyGenerator enemyGenerator = new EnemyGenerator(50, 2.5f, 100);
        menu StartMenu;
        menu PauseMenu;
        menu ExitMenu;
        Credits credits;

        Player player = new Player();
        List<int> ranAway = new List<int>();
        bool lose = false;

        Vector2 offSet = new Vector2(0, 618);
        public Game1() {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        
        protected override void Initialize() {
            // Screen
            graphics.PreferredBackBufferWidth = 1366;
            graphics.PreferredBackBufferHeight = 768;
            //graphics.IsFullScreen = true;
            graphics.ApplyChanges();

            screenWidth = GraphicsDevice.Viewport.Width;
            screenHeight = GraphicsDevice.Viewport.Height;

            explosion = new Explosion(this, 1);
            Components.Add(explosion);

            base.Initialize();
        }

        int enemyNum;
        Texture2D losebg;
        protected override void LoadContent() {
            // Font
            font       = Content.Load<SpriteFont>(@"Fonts\fonts");
            losebg = Content.Load<Texture2D>("losebg");
            // Level
            bg_layer0  = Content.Load<Texture2D>(@"Level\background_layer_0");
            bg_ground  = Content.Load<Texture2D>(@"Level\ground");
            bg_stair   = Content.Load<Texture2D>(@"Level\staircase");
            obj = Content.Load<Texture2D>(@"Level\mount");
            obj2 = Content.Load<Texture2D>(@"Level\BG2");
            obj3 = Content.Load<Texture2D>(@"Level\BG3");
            obj4 = Content.Load<Texture2D>(@"Level\BG4");
            obj5 = Content.Load<Texture2D>(@"Level\BG5_Unblurred");
            obj6 = Content.Load<Texture2D>(@"Level\iceberg");
            bg_mounts = Content.Load<Texture2D>(@"Level\mounts_bg");

            // GUI
            hp_mp_bar  = Content.Load<Texture2D>(@"GUI\hpBar");
            hp_mp_con  = Content.Load<Texture2D>(@"GUI\container");
           // skill_1    = Content.Load<Texture2D>(@"GUI\skillIcon_1");
            skill_2    = Content.Load<Texture2D>(@"GUI\skillIcon_2");
            skill_3    = Content.Load<Texture2D>(@"GUI\skillIcon_3");
            // Start Menu
            start_background = Content.Load<Texture2D>(@"Start Menu\sx");
            play_s     = Content.Load<Texture2D>(@"Start Menu\Select\Play_S");
            credits_s  = Content.Load<Texture2D>(@"Start Menu\Select\Credits_S");
            quit_s     = Content.Load<Texture2D>(@"Start Menu\Select\Quit_S");
            resume_s = Content.Load<Texture2D>(@"Start Menu\Select\Resume_S");
            resume_us = Content.Load<Texture2D>(@"Start Menu\Unselect\Resume_Us");
            play_us    = Content.Load<Texture2D>(@"Start Menu\Unselect\Play_Us");
            credits_us = Content.Load<Texture2D>(@"Start Menu\Unselect\Credits_Us");
            quit_us    = Content.Load<Texture2D>(@"Start Menu\Unselect\Quit_Us");

            startMenuMusic = Content.Load<Song>("Start Menu/startMenuMusic");
            // Items
            hpPot      = Content.Load<Texture2D>(@"Items\hpPot");
            //mpPot      =             player.Content.Load<Texture2D>(@"Items\mpPot");

            // Credits
            credits_bg = Content.Load<Texture2D>(@"Credits\background");
            
            // Constructor
            gui   = new GUI(font);
            level = new Level(screenWidth / 2, screenWidth, screenHeight, 2, 0.01f);
            levelMusic = Content.Load<Song>("Level/levelMusic");
            credits = new Credits(font, screenWidth, screenHeight);


            // Methods
            #region GUI
            gui.addItem(hp_mp_con, Vector2.Zero, "Container",  hp_mp_con.Width, hp_mp_con.Height);
            gui.addItem(hp_mp_bar, new Vector2(130, 56), "HP Bar", hp_mp_bar.Width, hp_mp_bar.Height);
            gui.addItem(hp_mp_bar, new Vector2(135, 88), "MP Bar", hp_mp_bar.Width, hp_mp_bar.Height / 2);
            gui.HP = 300;
            gui.MP = 150;
            gui.defMP = gui.MP;
            gui.mp_regenRate = 4000;
            #endregion

            #region Menus
            StartMenu = new menu(font);
            StartMenu.addMenuItem(play_s, play_us, new Vector2(100, 300));
            StartMenu.addMenuItem(credits_s, credits_us, new Vector2(100, 400));
            StartMenu.addMenuItem(quit_s, quit_us, new Vector2(100, 500));

            PauseMenu = new menu(font);
            PauseMenu.addMenuItem(resume_s, resume_us, new Vector2(500, 300));
            PauseMenu.addMenuItem(quit_s, quit_us, new Vector2(500, 425));
            //PauseMenu.addMenuItem(quit_s, quit_us, new Vector2(500, 550));

            ExitMenu = new menu(font);
            ExitMenu.addMenuItem(resume_s, resume_us, new Vector2(500, 300));
            ExitMenu.addMenuItem(quit_s, quit_us, new Vector2(500, 500));
            #endregion

            #region Level
            level.addItem(bg_layer0, Vector2.Zero, bg_layer0.Width, bg_layer0.Height, true);
            level.addItem(bg_layer0, Vector2.Zero, bg_layer0.Width, bg_layer0.Height, true);
            level.addItem(bg_ground, new Vector2(0, screenHeight - bg_ground.Height), bg_ground.Width, bg_ground.Height, false);
            level.addItem(bg_stair, new Vector2(0, screenHeight - (bg_stair.Height + bg_ground.Height) ), bg_stair.Width, bg_stair.Height, true);
            level.addItem(bg_mounts, new Vector2(-1600, screenHeight - (bg_mounts.Height + bg_ground.Height)), bg_mounts.Width, bg_mounts.Height, true);
            level.addItem(bg_mounts, new Vector2(-300, screenHeight - (bg_mounts.Height + bg_ground.Height)), bg_mounts.Width, bg_mounts.Height, true);

            enemyGenerator.addEnemy(Content);
            player.Load(Content);
            enemyNum = enemyGenerator.enemyNum;
            #endregion

            spriteBatch = new SpriteBatch(GraphicsDevice);
        }

        enum GameState {
            StartMenu,
            PauseMenu,
            Play,
            Credits,
            Exit
        }

        bool musicOn = true;

        GameState curGameState = GameState.StartMenu;
        GameState prevGameState;

        bool play = false;
        bool changeMusic = false;
        bool viewCredits = false;
        protected override void Update(GameTime gameTime) {
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
            UpdateExplosions(dt);

            KeyboardState key = Keyboard.GetState();

            if (curGameState == GameState.StartMenu) {
                prevGameState = GameState.StartMenu;
                exec_StartMenu(key, gameTime);
            }
            else if (curGameState == GameState.Credits) {
                prevGameState = GameState.Credits;
                exec_Credits(key, gameTime);
            }
            else if (curGameState == GameState.Play) {
                prevGameState = GameState.Play;
                exec_Play(key, oldKey, gameTime); 
            }
            else if (curGameState == GameState.PauseMenu) {
                exec_PauseMenu(key, gameTime); 
            }
            else if (curGameState == GameState.Exit) {
                exec_Exit(key, gameTime);
            }
            
            oldKey = key;
            base.Update(gameTime);
        }

        private void UpdateExplosions(float dt)
        {
            Vector2 where = Vector2.Zero;
            where.X = 600;
            where.Y = -150;
            explosion.AddParticles(where); 
        }

        private static Random random = new Random();

        public static Random Random
        {
            get { return random; }
        }

        public static float RandomBetween(float min, float max)
        {
            return min + (float)random.NextDouble() * (max - min);
        }

        public void Cutscene(){
            
        }

        protected override void Draw(GameTime gameTime) {
           GraphicsDevice device = graphics.GraphicsDevice;
           
           if (curGameState == GameState.StartMenu) {
               spriteBatch.Begin();
               spriteBatch.Draw(start_background, Vector2.Zero, new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
               spriteBatch.End();
               StartMenu.Draw(spriteBatch);
           }
           else if (curGameState == GameState.PauseMenu) {
               spriteBatch.Begin();
               spriteBatch.Draw(start_background, Vector2.Zero, new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
               spriteBatch.End();
               PauseMenu.Draw(spriteBatch);
           }
           else if (curGameState == GameState.Play) {
               level.DrawLevel(spriteBatch);
               gui.drawGUI(spriteBatch, gui.HP, gui.MP);
               
               player.Draw(spriteBatch);

               spriteBatch.Begin();
               if (lose) 
                   spriteBatch.Draw(losebg, new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
               spriteBatch.End();

               for (int i = 0; i < enemyNum; i++) {
                   if (enemyGenerator.HP[i] > 1)
                       enemyGenerator.drawEnemy(spriteBatch, i);
               }
               spriteBatch.Begin();
               if (win) spriteBatch.DrawString(font, " YOU WON! ", new Vector2(screenWidth / 2, screenHeight / 2), Color.Red);
               spriteBatch.End();
           }
           else if (curGameState == GameState.Credits) {
               credits.scrollCredits(spriteBatch, credits_bg, 1, Color.Black);
           }
           else if (curGameState == GameState.Exit) {
               spriteBatch.Begin();
               spriteBatch.Draw(start_background, Vector2.Zero, new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
               spriteBatch.End();
               ExitMenu.Draw(spriteBatch);
           }

           base.Draw(gameTime);
        }


        protected override void UnloadContent() {
        }

        #region Menu Functions
        public void exec_StartMenu(KeyboardState key, GameTime gameTime) {
            // Selecting Menu Options
            if (key.IsKeyDown(Keys.Down) && oldKey.IsKeyUp(Keys.Down)) StartMenu.selectNext();
            if (key.IsKeyDown(Keys.Up)   && oldKey.IsKeyUp(Keys.Up))   StartMenu.selectPrev();

            // Select menu options & jump to state accordingly
            if (key.IsKeyDown(Keys.Enter) && oldKey.IsKeyUp(Keys.Enter)) {
                if      (StartMenu.getSelectedName() == 0) curGameState = GameState.Play;
                else if (StartMenu.getSelectedName() == 1) curGameState = GameState.Credits;
                else if (StartMenu.getSelectedName() == 2) curGameState = GameState.Exit;
            }
            // If press Escape Exit
            if (key.IsKeyDown(Keys.Escape)) curGameState = GameState.Exit;

            if (musicOn) {
                // Play Level Music
                if (MediaPlayer.State == MediaState.Stopped)
                    MediaPlayer.Play(startMenuMusic);
            }
        }

        public void exec_Play(KeyboardState key, KeyboardState oldkey, GameTime gameTime) {
            if (key.IsKeyDown(Keys.Escape)) curGameState = GameState.PauseMenu;
            int skill_use = 0;
            // Game World / Player Updates
            offSet += player.mDirection * player.mSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            player.Update(gameTime);
            player.UpdatePlayerInput(key, oldKey);
            UpdateCollision(gameTime);
            level.UpdateLevel(player.feetPosition, player.mDirection, 180);
            ReachedScreenBound();
            checkWinCondition();
            checkSightDir();
            if (key.IsKeyDown(Keys.D1) && oldkey.IsKeyUp(Keys.D1))
                gui.MP -= 50;
            else skill_use = 0;
            gui.updateGUI(skill_use, gameTime);
            if (musicOn) {
                // Change music
                if (changeMusic == false) {
                    MediaPlayer.Stop();
                    changeMusic = true;
                }
                if (MediaPlayer.State == MediaState.Stopped)
                    MediaPlayer.Play(levelMusic);
            }
        }

        public void exec_PauseMenu(KeyboardState key, GameTime gameTime) {
            if (key.IsKeyDown(Keys.Down) && oldKey.IsKeyUp(Keys.Down)) 
                PauseMenu.selectNext();
            if (key.IsKeyDown(Keys.Up) && oldKey.IsKeyUp(Keys.Up))
                PauseMenu.selectPrev();

            // Select options in Menu ( Play, Exit )
            if (key.IsKeyDown(Keys.Enter) && oldKey.IsKeyUp(Keys.Enter)) {
                if (PauseMenu.getSelectedName() == 0)
                    curGameState = prevGameState;
                if (PauseMenu.getSelectedName() == 1)
                    curGameState = GameState.StartMenu;
               // if (PauseMenu.getSelectedName() == 2) 
                //    this.Exit();
                    
            }
            
            if (musicOn) {
                // Play Music
                if (MediaPlayer.State == MediaState.Stopped)
                    MediaPlayer.Play(startMenuMusic);
            }
        }

        public void exec_Credits(KeyboardState key, GameTime gameTime) {
            // Jumps back to menu if player presses Esc
            if (key.IsKeyDown(Keys.Escape)) {
                curGameState = GameState.PauseMenu;
            }
            if (musicOn) {
                // Play Credit Music
                if (MediaPlayer.State == MediaState.Stopped)
                    MediaPlayer.Play(startMenuMusic);
            }
        }

        public void exec_Exit(KeyboardState key, GameTime gameTime) {
            if (key.IsKeyDown(Keys.Down) && oldKey.IsKeyUp(Keys.Down))
                ExitMenu.selectNext();
            if (key.IsKeyDown(Keys.Up) && oldKey.IsKeyUp(Keys.Up))
                ExitMenu.selectPrev();
            
            if (key.IsKeyDown(Keys.Enter) && oldKey.IsKeyUp(Keys.Enter)) {
                if (ExitMenu.getSelectedName() == 0)
                    curGameState = prevGameState;
                if (ExitMenu.getSelectedName() == 1)
                    this.Exit();
            }
        }
        #endregion
        int left = 0;
        bool lol = false;
        #region Game World / Player Update functions
        public void checkWinCondition() {
            // Player dies
            if (gui.HP < 1) lose = true;
            
            // All enemy dies

        }

        public void checkSightDir() {
            if (player.SightDirection == "left") direction = -1;
            else direction = 1;
        }

        public void UpdateCollision(GameTime gameTime) {
            playerRect = new Rectangle((int)player.feetPosition.X + 12, (int)player.feetPosition.Y, 100, 128);

            for (int i = 0; i < enemyNum; i++) {

                if (enemyGenerator.HP[i] > 1) {
                    enemyGenerator.updateEnemy(player.feetPosition, gameTime, i);

                    if (playerRect.Intersects(enemyGenerator.enemyRect[i]) && player.DmgAnimation) {
                        if (!player.EndNormalAttack)
                            enemyGenerator.HP[i] -= 90;

                        player.EndNormalAttack = true;
                        enemyGenerator.enemy[i].getHitState = true;

                        if (player.ATkHitSEIns.State != SoundState.Playing)
                            player.ATkHitSEIns.Play();
                    }

                    if (player.Fireball.rect.Intersects(enemyGenerator.enemyRect[i]) && player.DmgAnimation) {
                        if (!player.EndNormalAttack)
                            enemyGenerator.HP[i] -= 110;

                        player.EndNormalAttack = true;
                        enemyGenerator.enemy[i].getHitState = true;
                    }

                    if (enemyGenerator.enemyRect[i].Intersects(playerRect) && enemyGenerator.atkAnimation) {
                        if (!player.getHitState)
                            gui.HP -= 30;
                        player.getHitState = true;
                    }
                }
                else enemyGenerator.dead[i] = true;
            }
        }

        protected void ReachedScreenBound() {
            if (player.feetPosition.X > screenWidth - 780) {
                player.feetPosition.X = screenWidth - 780;
            }
            if (player.feetPosition.X < 60) {
                player.feetPosition.X = 60;
            }

            if (player.feetPosition.Y > screenHeight - 60)
                player.feetPosition.Y = screenHeight - 60;
            if (player.feetPosition.Y < 60)
                player.feetPosition.Y = 60;
        }
        #endregion
    }
}
